package org.jeecg.modules.xxgx.common.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.modules.innerApi.common.requestDto.InvoiceParam;
import org.jeecg.modules.innerApi.common.requestDto.InvoicemxParam;
import org.jeecg.modules.xxgx.common.enums.*;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

public class InvoiceParamValid {
    //数子字母验证
    private static final Pattern GREP_NUM_LETTER = Pattern.compile("[0-9a-zA-Z]+");

    /**
     * 发票开具参数校验
     * @param invoiceParam
     * @return
     * @throws UnsupportedEncodingException
     */
    public static Result checkInvoiceParam(InvoiceParam invoiceParam) {
        {
            List<String> errorList = new ArrayList<>();
            try {
                String fplxdm = StringUtils.trimToEmpty(invoiceParam.getFplxdm());
                if (StringUtils.isEmpty(fplxdm))
                    errorList.add("请填写发票类型代码!");
                //票种验证
                if (!CollUtil.newHashSet("004", "007", "026", "025", "009", "028", "01", "02").contains(fplxdm))
                    errorList.add("票种参数不正确!");
                /**
                 * 特殊票种 00-不是   01-农产品销售  02-农产品收购 06-抵扣通行费 07-其它通行费 08-成品油销售
                 * 02-收购类型，销方、购方验证信息对调
                 */
                String tspz = StringUtils.trimToEmpty(invoiceParam.getTspz());
                //String djkp = StringUtils.trimToEmpty(jsonObject.getString("djkp"));
                /**
                 * 销方验证
                 * 卷式发票无需验证：销货单位地址电话、销货单位银行账号
                 */
                //销货单位识别号
                String xfnsrsbh = invoiceParam.getXfsh();
                Integer xfnsrsbhLenth = null;
                if (StrUtil.isBlank(xfnsrsbh)) {
                    errorList.add("请填写" + (TspzEnum.NCPSG.getValue().equals(tspz) ? "购货" : "销货") + "单位识别号!");
                } else {
                    xfnsrsbhLenth = xfnsrsbh.getBytes("GBK").length;
                    if (xfnsrsbhLenth < 15 || xfnsrsbhLenth > 20) {
                        errorList.add((TspzEnum.NCPSG.getValue().equals(tspz) ? "购货" : "销货") + "单位识别号长度最少15位，最多20位，当前" + xfnsrsbhLenth + "位！");
                    } else if (!GREP_NUM_LETTER.matcher(xfnsrsbh).matches())
                        errorList.add((TspzEnum.NCPSG.getValue().equals(tspz) ? "购货" : "销货") + "单位识别号仅支持数字、字母!");
                }
                //销货单位名称
                String xfmc = invoiceParam.getXfmc();
                if (StrUtil.isBlank(xfmc)) {
                    errorList.add("请填写" + (TspzEnum.NCPSG.getValue().equals(tspz) ? "购货" : "销货") + "单位名称!");
                } else if (xfmc.getBytes("GBK").length > 100)
                    errorList.add((TspzEnum.NCPSG.getValue().equals(tspz) ? "购货" : "销货") + "单位名称长度最多100位，当前" + xfmc.getBytes("GBK").length + "位！");
                //销货单位地址电话
                String xfdzdh = invoiceParam.getXfdzdh();
                if (StrUtil.isBlank(xfdzdh) && !(FplxdmEnum.zzsjsfp.getValue().equals(fplxdm) || TspzEnum.NCPSG.getValue().equals(tspz))) {
                    errorList.add("请填写" + (TspzEnum.NCPSG.getValue().equals(tspz) ? "购货" : "销货") + "单位地址电话!");
                } else if (!FplxdmEnum.zzsjsfp.getValue().equals(fplxdm) && xfdzdh.getBytes("GBK").length > 100)
                    errorList.add((TspzEnum.NCPSG.getValue().equals(tspz) ? "购货" : "销货") + "单位地址电话长度最多100!位，当前" + xfdzdh.getBytes("GBK").length + "位！");
                //销货单位银行账号
                String xfyhzh = invoiceParam.getXfyhzh();
                if (StrUtil.isBlank(xfyhzh) && !(FplxdmEnum.zzsjsfp.getValue().equals(fplxdm) || TspzEnum.NCPSG.getValue().equals(tspz))) {
                    errorList.add("请填写销货单位银行账号!");
                } else if (!FplxdmEnum.zzsjsfp.getValue().equals(fplxdm) && xfyhzh.getBytes("GBK").length > 100)
                    errorList.add("销货单位银行账号长度最多100位，当前" + xfyhzh.getBytes("GBK").length + "位！");

                /**
                 * 购方验证
                 * 专票需验证：购货单位识别号、购货单位地址电话、购货单位银行账号
                 */
                //购货单位识别号
                if (FplxdmEnum.zzszp.getValue().equals(fplxdm)) {
                    String gfnsrsbh = invoiceParam.getKhsh();
                    Integer gfnsrsbhLenth = null;
                    if (StrUtil.isNotBlank(gfnsrsbh))
                        gfnsrsbhLenth = gfnsrsbh.getBytes("GBK").length;
                    if (StrUtil.isBlank(gfnsrsbh)) {
                        errorList.add("请填写购货单位识别号!");
                    } else if (StrUtil.isNotBlank(gfnsrsbh) && (gfnsrsbhLenth < 15 || gfnsrsbhLenth > 20)) {
                        errorList.add("购货单位识别号长度最少15位，最多20位，当前" + gfnsrsbhLenth + "位！");
                    } else if (StrUtil.isNotBlank(gfnsrsbh) && !GREP_NUM_LETTER.matcher(gfnsrsbh).matches())
                        errorList.add("购货单位识别号仅支持数字、字母!");
                    //购货单位地址电话
                    String gfdzdh = invoiceParam.getKhdzdh();
                    if (StrUtil.isBlank(gfdzdh) && FplxdmEnum.zzszp.getValue().equals(fplxdm)) {
                        errorList.add("请填写购货单位地址电话!");
                    } else if (!FplxdmEnum.zzsjsfp.getValue().equals(fplxdm) && StrUtil.isNotBlank(gfdzdh) && gfdzdh.getBytes("GBK").length > 100)
                        errorList.add("购货单位地址电话长度最多100位，当前" + gfdzdh.getBytes("GBK").length + "位！");
                    //购货单位银行账号
                    String gfyhzh = invoiceParam.getKhyhzh();
                    if (StrUtil.isBlank(gfyhzh) && FplxdmEnum.zzszp.getValue().equals(fplxdm)) {
                        errorList.add("请填写购货单位银行账号!");
                    } else if (!FplxdmEnum.zzsjsfp.getValue().equals(fplxdm) && StrUtil.isNotBlank(gfyhzh) && gfyhzh.getBytes("GBK").length > 100)
                        errorList.add("购货单位银行账号长度最多100位，当前" + gfyhzh.getBytes("GBK").length + "位！");
                }
                //购货单位名称
                String gfmc = invoiceParam.getKhmc();
                if (StrUtil.isBlank(gfmc)) {
                    errorList.add("请填写" + (TspzEnum.NCPSG.getValue().equals(tspz) ? "销货" : "购货") + "单位名称!");
                } else if (gfmc.getBytes("GBK").length > 100)
                    errorList.add((TspzEnum.NCPSG.getValue().equals(tspz) ? "销货" : "购货") + "单位名称长度最多100位，当前" + gfmc.getBytes("GBK").length + "位！");

                String zsfs = invoiceParam.getZsfs();  //征收方式

               /*  因不同发票类型的负数发票与正数发票 且不同的税控服务器 备注字段长度检验均不一致，临时去掉备注的检验
               String bz = jsonObject.getString("bz");      //备注
               if("2".equals(zsfs) && StrUtil.isNotBlank(bz)){
                    if(bz.getBytes("GBK").length > 160)
                        errorList.add("备注长度最多160位，当前" + bz.getBytes("GBK").length + "位！");
                }else if(StrUtil.isNotBlank(bz)){
                    if(bz.getBytes("GBK").length > 184)
                        errorList.add("备注长度最多184位，当前"+ bz.getBytes("GBK").length + "位！");
                }*/
                //收款人、复核人
                String skr = invoiceParam.getSkr();
                String fhr = invoiceParam.getFhr();
                //收款人验证
                /*if(StringUtils.isEmpty(skr)){
                    errorList.add("请填写收款人!");
                }else */
                if (StringUtils.isNotBlank(skr) && skr.getBytes("GBK").length > 16)
                    errorList.add("收款人长度最多16位，当前" + skr.getBytes("GBK").length + "位！");
                //复核人验证
                /*if(!"025".equals(fplxdm) && StringUtils.isEmpty(fhr)){
                    errorList.add("请填写复核人!");
                }else */
                if (!FplxdmEnum.zzsjsfp.getValue().equals(fplxdm) && StringUtils.isNotBlank(fhr) && fhr.getBytes("GBK").length > 16)
                    errorList.add("复核人长度最多16位，当前" + fhr.getBytes("GBK").length + "位！");
                //开票人验证
                String kpr = invoiceParam.getKpr();
                /*if (StringUtils.isEmpty(kpr)) {
                    errorList.add("请填写开票人!");
                }else */
                if (StringUtils.isNotBlank(kpr) && kpr.getBytes("GBK").length > 20)
                    errorList.add("开票人长度不能超过20位，当前" + kpr.getBytes("GBK").length + "位！");

                /**
                 * 数据合法性验证
                 * 含税金额不能为0
                 * 负数发票税额不能大于0
                 * 正数发票税额不能小于零
                 * 专票负数发票，通知单编号不能为空
                 */
                BigDecimal hjje = invoiceParam.getHjje();
                if (hjje.compareTo(BigDecimal.ZERO) == 0)
                    errorList.add("不含税总金额不为能为0!");
                String kplx = StringUtils.trimToEmpty(invoiceParam.getKplx()); //'0正数发票，1负数发票，2空白发票，3正数作废发票，4负数作废发票',
                if ("".equals(kplx)) {
                    kplx = hjje.compareTo(BigDecimal.ZERO) > 0 ? KplxEnum.ZSFP.getValue() : KplxEnum.FSFP.getValue();
                    invoiceParam.setKplx(kplx);
                }
                //负数发票验证
                if (KplxEnum.FSFP.getValue().equals(kplx)) {
                    String yfpdm = StringUtils.trimToEmpty(invoiceParam.getYfpdm());
                    String yfphm = StringUtils.trimToEmpty(invoiceParam.getYfphm());
//            if (StrUtil.hasBlank(yfpdm,yfphm))
//                errorList.add("开具负数发票时，对应蓝票代码、号码不能为空!");

                    //专票通知单编号不能为空
                    if (FplxdmEnum.zzszp.getValue().equals(fplxdm) || FplxdmEnum.dzzp.getValue().equals(fplxdm)
                            || FplxdmEnum.sdzp.getValue().equals(fplxdm) || FplxdmEnum.sdpp.getValue().equals(fplxdm)) {
                        if (StringUtils.isEmpty(invoiceParam.getHzxxbbh())) {
                            //errorList.add("专票通知单编号不能为空!");
                            errorList.add("红字申请单编号不能为空!");
                        }
                    }
                    if(FplxdmEnum.sdzp.getValue().equals(fplxdm) || FplxdmEnum.sdpp.getValue().equals(fplxdm)){
                        //数电校验原发票代码、号码
                        if (StringUtils.isEmpty(yfphm)) {
                            errorList.add("开具负数发票时，对应蓝票号码不能为空!");
                        }
                    } else {
                        if (StringUtils.isEmpty(yfpdm) || StringUtils.isEmpty(yfphm)) {
                            errorList.add("开具负数发票时，对应蓝票代码、号码不能为空!");
                        }
                    }
                }
                //正数发票金额大于0，负数发票金额小于0
                if (hjje.compareTo(BigDecimal.ZERO) != 0) {
                    if ((KplxEnum.FSFP.getValue().equals(kplx) && hjje.compareTo(BigDecimal.ZERO) > 0) || (KplxEnum.ZSFP.getValue().equals(kplx) && hjje.compareTo(BigDecimal.ZERO) < 0)) {
                        errorList.add("开票类型与开票金额不相符!");
                    }
                }

                /**
                 * 明细校验
                 * 校验项：商品名称、规格型号、单位、税收编码、不含税金额
                 * 折扣行，商品名称须与被折扣行的商品名称相同，不能多行折扣
                 */
                List<InvoicemxParam> invoicemxParamList = invoiceParam.getFpmxs();
                for (int i = 0; i < invoicemxParamList.size(); i++) {
                    InvoicemxParam djmx = invoicemxParamList.get(i);
                    //商品名称校验
                    String spmc = djmx.getSpmc();
                    //跳过清单数据
                    if (StrUtil.isNotBlank(spmc) && (spmc.contains("详见销货清单") || spmc.contains("详见对应正数发票及清单")))
                        continue;
                    if (StrUtil.isBlank(djmx.getTax().toPlainString())) {
                        errorList.add(String.format("请输入第%s行税率！", i + 1));
                    }
                    //折扣行名称校验
                    if (FphxzEnum.BZKH.getValue().equals(djmx.getFphxz())) {     //被折行数据
                        InvoicemxParam zhsj = invoicemxParamList.get(i + 1); //找出对应的折行数据
                        if (!djmx.getSpmc().equals(zhsj.getSpmc()))
                            errorList.add(String.format("第%s行商品名称与第%s行折扣名称不一致！", i + 1, i + 2));
                    }
                    //商品名称校验
                    if (StrUtil.isBlank(spmc)) {
                        errorList.add(String.format("请输入第%s行商品名称！", i + 1));
                    } else if (spmc.getBytes("GBK").length > 80) {
                        errorList.add(String.format("第%s行商品名称长度超限，最多80位，当前%s位！", i + 1, spmc.getBytes("GBK").length));
                    }
                    //规格型号
                    String ggxh = djmx.getGgxh();
                    if (StrUtil.isNotBlank(ggxh) && ggxh.getBytes("GBK").length > 40)
                        errorList.add(String.format("第%s行商品规格长度超限，最多40位，当前%s位！", i + 1, ggxh.getBytes("GBK").length));
                    //增加机动车专票数量校验
                    if (StringUtils.equals(fplxdm, FplxdmEnum.zzszp.getValue()) && StringUtils.equals(tspz, TspzEnum.JDC.getValue()) && djmx.getSpsl() != null) {
                        //去掉小数位变为整数
                        BigDecimal spsl = djmx.getSpsl();
                        djmx.setSpsl(spsl.stripTrailingZeros());
                    }
                    BigDecimal spsl = djmx.getSpsl();
                    if (!FphxzEnum.ZKH.getValue().equals(djmx.getFphxz())) {
                        if(spsl == null || spsl.compareTo(BigDecimal.ZERO) == 0){
                            errorList.add(String.format("第%s行商品数量不能为空！", i + 1));
                        }
                    }
                        //单位
                    String dw = djmx.getJldw();
                    if (StrUtil.isNotBlank(dw) && dw.getBytes("GBK").length > 14)
                        errorList.add(String.format("第%s行商品单位长度超限，最多14位，当前%s位！", i + 1, dw.getBytes("GBK").length));



                    //税收编码item.getString("ssbm")
                    String ssbm = djmx.getSpbm();
                    if (StrUtil.isBlank(ssbm)) {
                        errorList.add(String.format("第%s行商品缺少税收编码！", i + 1));
                    }
                    //校验金额 cwgx todo:待完善
                    BigDecimal bhsje = djmx.getBhsje();//不含税金额
                    BigDecimal hsje = djmx.getHsje();//含税金额
                    BigDecimal bhsdj = djmx.getBhsdj();//不含税单价
                    BigDecimal hsdj = djmx.getHsdj();//含税单价
                    BigDecimal taxje = djmx.getTaxje();//税额
                    if (taxje == null) {
                        errorList.add(String.format("第%s行商品缺少税额！", i + 1));
                    }
                    if(HsbzEnum.N.getValue().equals(invoiceParam.getHsbz())) {
                        if (bhsje == null || bhsje.compareTo(BigDecimal.ZERO) == 0) {
                            errorList.add(String.format("第%s行商品缺少不含税金额！", i + 1));
                        }
                        if (!FphxzEnum.ZKH.getValue().equals(djmx.getFphxz())) {//非折扣行
                            if (bhsdj == null || bhsdj.compareTo(BigDecimal.ZERO) == 0) {
                                errorList.add(String.format("第%s行商品缺少不含税单价！", i + 1));
                            }

                        }
                    } else {

                    }


                }


                //设置合计税率
            /*if (mxsls.size() == 1) {
                jsonObject.put("zhsl", mxsls.stream().findFirst().orElse(""));
            } else if (mxsls.size() > 1) {
                jsonObject.put("zhsl", "99.01");//多税率固定为99.01
            }*/
                //小规模纳税人标识
            /*Boolean xgmnsr = jsonObject.getBoolean("xgmnsr");
            if (xgmnsr) {
                //小规模纳税人 免税优惠政策时间段
                String yhsj = StringUtilsExt.getString(CommonUtil.getXtcsz("xx_xgmnsr_yhsj"), "");
                boolean isYhqj = false;
                if (StringUtil.isNotEmpty(yhsj) && yhsj.contains(",")) {
                    String[] xgmnsryh = yhsj.split(",");
                    Date xgmnsrYhks = DateUtil.parse(xgmnsryh[0], "yyyy-MM-dd");
                    Date xgmnsrYhjs = DateUtil.parse(xgmnsryh[1], "yyyy-MM-dd");
                    Date currentDate = DateUtil.parse(DateUtil.format(new Date(), "yyyy-MM-dd"), "yyyy-MM-dd");
                    if (currentDate.compareTo(xgmnsrYhks) >= 0 && currentDate.compareTo(xgmnsrYhjs) <= 0) {
                        isYhqj = true;
                    }
                }
             *//* 小规模、转登记纳税人2022年12月31日前3%税率开具发票理由
            （1）开具发票为2022年3月31日前发生纳税义务的业务；
            （2）前期已开具相应征收率发票，发生销售折让、中止或者退回等情形需要开具红字发票，或者开票有误需要重新开具；
            （3）因为实际经营业务需要，放弃享受免征增值税政策。*//*
                String sslkjly = jsonObject.getString("sslkjly");
                if (mxsls.contains("0.03") && StringUtil.isEmpty(sslkjly)) {
                    errorList.add("请选择小规模、转登记纳税人2022年12月31日前3%税率开具发票理由!");
                }
            }*/

                if (errorList.size() > 0)
                    return Result.error(-1, JSON.toJSONString(errorList));

                return Result.ok("验证通过");
            }catch (Exception e){
                return Result.error("参数校验未通过!" + StringUtils.join(errorList.toArray()));
            }
        }
    }
}
